package com.niiwoo.civet.account.service.local.openAccount;

import com.niiwoo.civet.account.constant.AccountRegisterErrorCode;
import com.niiwoo.civet.account.dao.entity.AccountBase;
import com.niiwoo.civet.account.dao.entity.AccountPerson;
import com.niiwoo.civet.account.dao.entity.BankCard;
import com.niiwoo.civet.account.dao.entity.GroupAccountCorrelateOrder;
import com.niiwoo.civet.account.dao.entity.OpenAccountRecord;
import com.niiwoo.civet.account.dto.common.LanMaoGatewayRequestDTO;
import com.niiwoo.civet.account.dto.request.CreateRegisterOrderRequestDTO;
import com.niiwoo.civet.account.dto.request.UpdateGroupAccountCorrelateRequestDTO;
import com.niiwoo.civet.account.dto.response.UpdateGroupRegisterOrderResponseDTO;
import com.niiwoo.civet.account.enums.AccountActiveEnum;
import com.niiwoo.civet.account.enums.AccountTypeEnum;
import com.niiwoo.civet.account.enums.GroupAccountCorrelateOrderStatusEnum;
import com.niiwoo.civet.account.enums.OpenAccountRecordStatusEnum;
import com.niiwoo.civet.account.enums.OpenAccountWayEnum;
import com.niiwoo.civet.account.service.local.AccountPersonService;
import com.niiwoo.civet.account.service.local.BankCardService;
import com.niiwoo.civet.account.service.local.GroupAccountCorrelateOrderService;
import com.niiwoo.civet.account.service.local.OpenAccountRecordService;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.lanmao.component.LanMaoGatewayService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.CredentialsTypeEnum;
import com.niiwoo.tripod.lanmao.enums.GroupAccountCorrelateTypeEnum;
import com.niiwoo.tripod.lanmao.enums.UserAuthorizationEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

//@Component
public class GroupOpenAccountService extends AbstractOpenAccountService<UpdateGroupAccountCorrelateRequestDTO, UpdateGroupRegisterOrderResponseDTO> {

    private static final List<UserRoleEnum> SUPPORT_ROLE_LIST = Arrays.asList(UserRoleEnum.INVESTOR, UserRoleEnum.BORROWERS);

    private static final List<OpenAccountWayEnum> SUPPORT_WAY_LIST = Arrays.asList(OpenAccountWayEnum.GROUP_ACCOUNT_CORRELATE, OpenAccountWayEnum.R360_GROUP_ACCOUNT_CORRELATE);

    @Autowired
    OpenAccountTemplate openAccountTemplate;

    @Autowired
    GroupAccountCorrelateOrderService groupAccountCorrelateOrderService;

    @Autowired
    SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    OpenAccountRecordService openAccountRecordService;

    @Autowired
    BankCardService bankCardService;

    @Autowired
    PrivacyMasks privacyMasks;

    @Autowired
    AccountPersonService accountPersonService;

    @Autowired
    LanMaoSequence lanMaoSequence;

    @Autowired
    LanMaoGatewayService lanMaoGatewayService;

    @Override
    protected LanMaoGatewayRequestDTO internalCreateOrder(CreateRegisterOrderRequestDTO requestDTO) {
        // 查询开户记录
        List<OpenAccountRecord> recordList = Optional.ofNullable(openAccountRecordService.getByUserId(requestDTO.getUserId())).orElse(Collections.EMPTY_LIST);

        Optional<OpenAccountRecord> currentRoleRecordOpt = recordList.stream()
                .filter(r -> Objects.equals(r.getAccountRole(), requestDTO.getAccountRole().getValue()))
                .findFirst();
        // 存在且成功则，则返回异常
        currentRoleRecordOpt.ifPresent(r -> {
            switch (OpenAccountRecordStatusEnum.of(r.getStatus())) {
                case AUDITING:
                    throw new BizException(AccountRegisterErrorCode.ACCOUNT_AUDITING);
                case SUCCESS:
                    throw new BizException(AccountRegisterErrorCode.HAS_REGISTERED_ACCOUNT);
            }
        });
        // 查询个人绑卡注册成功记录
        OpenAccountRecord preSuccessRecord = recordList.stream()
                .filter(r -> Objects.equals(r.getStatus(), OpenAccountRecordStatusEnum.SUCCESS.getValue()))
                .findFirst()
                .orElseThrow(() -> new BizException(AccountRegisterErrorCode.SUCCESS_RECORD_NOT_EXISTS));
        Optional<AccountBase> accountBaseOptional = Optional.ofNullable(openAccountRecordService.getAccountBase(requestDTO.getUserId(), requestDTO.getAccountRole()))
                .filter(b -> b.getImportUserActiva().equals(AccountActiveEnum.UNACTIVATED.getValue()));
        // 获取更新或初始化开户记录
        OpenAccountRecord record = AccountEntityBuilder.buildRefreshOpenAccountRecord(
                currentRoleRecordOpt,
                () -> snowflakeIdWorker.nextId(),
                // 如果存在待激活的账户，则使用其账户编号
                () -> accountBaseOptional.map(AccountBase::getAccountNo).orElse(String.valueOf(snowflakeIdWorker.nextId())),
                preSuccessRecord.getGroupAccountNo(),
                requestDTO);
        // 权限
        Set<String> authList = openAccountTemplate.getAuthSetByRole(requestDTO.getAccountRole());
        accountBaseOptional.ifPresent(accountBase -> {
            if (accountBase.getTender().equals((byte) 1)) {
                authList.add(UserAuthorizationEnum.TENDER.name());
            }
            if (accountBase.getRepayment().equals((byte) 1)) {
                authList.add(UserAuthorizationEnum.REPAYMENT.name());
            }
            if (accountBase.getCreditAssignment().equals((byte) 1)) {
                authList.add(UserAuthorizationEnum.CREDIT_ASSIGNMENT.name());
            }
            if (accountBase.getCompensatory().equals((byte) 1)) {
                authList.add(UserAuthorizationEnum.COMPENSATORY.name());
            }
            if (accountBase.getWithdraw().equals((byte) 1)) {
                authList.add(UserAuthorizationEnum.WITHDRAW.name());
            }
            if (accountBase.getRecharge().equals((byte) 1)) {
                authList.add(UserAuthorizationEnum.RECHARGE.name());
            }
        });
        // 创建订单
        GroupAccountCorrelateOrder order = AccountEntityBuilder.buildInitGroupAccountCorrelateOrder(
                snowflakeIdWorker.nextId(),
                lanMaoSequence.getRequestNo(),
                currentRoleRecordOpt.orElse(record).getAccountNo(),
                preSuccessRecord.getGroupAccountNo(),
                requestDTO,
                String.join(",", authList)
        );
        // 更新开户记录和订单
        if (!openAccountRecordService.saveRecordAndAccountOrder(currentRoleRecordOpt.isPresent(), record, () -> groupAccountCorrelateOrderService.saveOrder(order))) {
            throw new BizException(AccountRegisterErrorCode.CREATE_ACCOUNT_REGISTER_ORDER_FAIL);
        }
        // 如果关联账户是待激活，则使用激活并关联，否则使用注册并关联
        GroupAccountCorrelateTypeEnum type = accountBaseOptional.isPresent() ? GroupAccountCorrelateTypeEnum.ACTIVE_AUTH : GroupAccountCorrelateTypeEnum.REGISTER_AUTH;
        // 封装网关请求参数
        return AccountLanMaoGatewayRequestBuilder.newGroupAccountCorrelateRequest(req -> lanMaoGatewayService.groupAccountCorrelate(req), order, type, requestDTO.getRedirectUrl());
    }

    @Override
    public UpdateGroupRegisterOrderResponseDTO updateOrder(UpdateGroupAccountCorrelateRequestDTO requestDTO) {
        return doUpdateOrder(
                () -> groupAccountCorrelateOrderService.getByRequestNo(requestDTO.getRequestNo()),
                order -> GroupAccountCorrelateOrderStatusEnum.except(order.getStatus(), GroupAccountCorrelateOrderStatusEnum.SUCCESS),
                order -> {
                    UpdateGroupRegisterOrderResponseDTO responseDTO = new UpdateGroupRegisterOrderResponseDTO();
                    responseDTO.setOrderId(order.getId());
                    responseDTO.setRequestNo(order.getRequestNo());
                    responseDTO.setOrderStatus(GroupAccountCorrelateOrderStatusEnum.SUCCESS);
                    return responseDTO;
                },
                order -> openAccountRecordService.getByUserIdAndRole(order.getUserId(), UserRoleEnum.enumOf(order.getUserRole())),
                (order, record) -> {
                    UpdateGroupRegisterOrderResponseDTO responseDTO = new UpdateGroupRegisterOrderResponseDTO();
                    responseDTO.setOrderId(order.getId());
                    responseDTO.setRequestNo(order.getRequestNo());
                    GroupAccountCorrelateOrderStatusEnum orderStatus;
                    switch (requestDTO.getStatus()) {
                        case SUCCESS: {
                            orderStatus = updateSuccessOrder(record, order, requestDTO);
                        }
                        break;
                        case FAILURE: {
                            orderStatus = updateFailOrder(record, order, requestDTO);
                        }
                        break;
                        default:
                            orderStatus = GroupAccountCorrelateOrderStatusEnum.of(order.getStatus());
                    }
                    responseDTO.setOrderStatus(orderStatus);
                    return responseDTO;
                }
        );
    }

    @Override
    protected List<UserRoleEnum> getSupportRole() {
        return SUPPORT_ROLE_LIST;
    }

    @Override
    protected List<OpenAccountWayEnum> getSupportWay() {
        return SUPPORT_WAY_LIST;
    }

    private GroupAccountCorrelateOrderStatusEnum updateSuccessOrder(OpenAccountRecord record, GroupAccountCorrelateOrder order, UpdateGroupAccountCorrelateRequestDTO requestDTO) {
        BankCard preBankCard = bankCardService.getSimpleUserBankCard(record.getUserId());
        Optional<AccountBase> baseOptional = Optional.ofNullable(openAccountRecordService.getAccountBase(record.getUserId(), UserRoleEnum.enumOf(record.getAccountRole())));
        Set<String> authSet = Optional.ofNullable(order.getAuthList())
                .map(list -> {
                    Set<String> set = new HashSet<>(Arrays.asList(list.split(",")));
                    return set;
                })
                .orElse(Collections.EMPTY_SET);
        AccountBase accountBase = baseOptional.isPresent() ? AccountEntityBuilder.buildActivateAccountBase(baseOptional.get(), authSet) : AccountEntityBuilder.buildInitAccountBase(snowflakeIdWorker.nextId(), record, AccountTypeEnum.PERSONAL, authSet);
        AccountPerson person = baseOptional.isPresent() ? AccountEntityBuilder.buildActivateAccountPerson(baseOptional.get().getId(), preBankCard.getRealName(), preBankCard.getIdCard()) : AccountEntityBuilder.buildInitAccountPerson(record, accountBase, preBankCard.getRealName(), preBankCard.getIdCard(), CredentialsTypeEnum.PRC_ID);
        boolean isSuccess = openAccountTemplate.doHandleSuccessOrder(
                record,
                requestDTO.getGroupAccountNo(),
                () -> groupAccountCorrelateOrderService.updateOrder(AccountEntityBuilder.buildUpdateGroupAccountCorrelateOrder(true, order, requestDTO)),
                !baseOptional.isPresent(),
                accountBase,
                () -> baseOptional.isPresent()? accountPersonService.update(person) : accountPersonService.save(person),
                () -> true
        );
        return isSuccess ? GroupAccountCorrelateOrderStatusEnum.SUCCESS : GroupAccountCorrelateOrderStatusEnum.of(order.getStatus());
    }

    private GroupAccountCorrelateOrderStatusEnum updateFailOrder(OpenAccountRecord record, GroupAccountCorrelateOrder order, UpdateGroupAccountCorrelateRequestDTO requestDTO) {
        boolean isSuccess = openAccountTemplate.doHandleUnSuccessOrder(
                record,
                OpenAccountRecordStatusEnum.FAILURE,
                () -> groupAccountCorrelateOrderService.updateOrder(AccountEntityBuilder.buildUpdateGroupAccountCorrelateOrder(false, order, requestDTO)),
                requestDTO.getErrorCode(),
                requestDTO.getErrorMessage()
        );
        return isSuccess ? GroupAccountCorrelateOrderStatusEnum.FAILURE : GroupAccountCorrelateOrderStatusEnum.of(order.getStatus());
    }

}
